Android局域网实现FTP文件上传下载客户端与服务端

您所在的位置:网站首页 ftp 安卓我下载 Android局域网实现FTP文件上传下载客户端与服务端

Android局域网实现FTP文件上传下载客户端与服务端

2024-07-15 01:35| 来源: 网络整理| 查看: 265

文章目录 前言一、FTP是什么?二、使用步骤1 服务端1.1 服务端的代码实现 2 客户端2.1 客户端的代码实现 附件

前言

最近在公司的项目中,使用到了 局域网通信,不同的设备直接传递消息以及发送文件。普通文本消息的发送使用websocket 封装了一套可以使用,但是对于文件类型的消息,尤其是大文件的发送,使用websocket 发送字节数组的形式出现了很多的问题,所以就取消了使用websocket 自己封装发送的方式。采用局域网

一、FTP是什么?

FTP(File Transfer Protocol,文件传输协议) 是 TCP/IP 协议组中的协议之一。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。 其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。在开发网站的时候,通常利用FTP协议把网页或程序传到Web服务器上。此外,由于FTP传输效率非常高,在网络上传输大的文件时,一般也采用该协议

二、使用步骤 1 服务端

引入库:

//ftp server implementation files('libs/ftpserver-core-1.0.6.jar') implementation files('libs/mina-core-2.0.16.jar') implementation 'commons-net:commons-net:3.8.0' 1.1 服务端的代码实现

FtpServerlet:

import androidx.annotation.Keep import org.apache.ftpserver.FtpServer import java.io.File import org.apache.ftpserver.listener.ListenerFactory import org.apache.ftpserver.FtpServerFactory import org.apache.ftpserver.ftplet.* import org.apache.ftpserver.usermanager.SaltedPasswordEncryptor import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory import org.apache.ftpserver.usermanager.impl.WritePermission import org.apache.ftpserver.usermanager.impl.BaseUser @Keep class FtpServerlet( private val sharedDirectory: String, private val ftpPort: Int = 2121, private val log: ((tag: String, content: String?) -> Unit)?=null ) : DefaultFtplet() { private val TAG = "FtpServerlet" private var mFtpServer: FtpServer? = null private val mUser = "myUser" private val mPassword = "myPassword" fun startFtp() { if (null != mFtpServer && !mFtpServer!!.isStopped) { return } val file = File(sharedDirectory) if (!file.exists()) { file.mkdirs() } val serverFactory = FtpServerFactory() val listenerFactory = ListenerFactory() // 设定端末番号 listenerFactory.port = ftpPort // 通过PropertiesUserManagerFactory创建UserManager然后向配置文件添加用户 val userManagerFactory = PropertiesUserManagerFactory() userManagerFactory.passwordEncryptor = SaltedPasswordEncryptor() val userManager: UserManager = userManagerFactory.createUserManager() val auths = mutableListOf() val auth: Authority = WritePermission() auths.add(auth) //添加用户 val user = BaseUser() user.name = mUser user.password = mPassword user.homeDirectory = sharedDirectory user.authorities = auths userManager.save(user) // 设定Ftplet val ftpletMap = mutableMapOf() ftpletMap["Ftplet"] = this serverFactory.userManager = userManager; serverFactory.addListener("default", listenerFactory.createListener()); // serverFactory.ftplets = ftpletMap mFtpServer = serverFactory.createServer(); mFtpServer?.start() log?.invoke(TAG, "start ftp server , sharedDirectory = $sharedDirectory") } fun stopFtp() { // FtpServer不存在和FtpServer正在运行中 if (null != mFtpServer && !mFtpServer!!.isStopped) { mFtpServer?.stop() log?.invoke(TAG, "stop ftp server") } } override fun onAppendStart(session: FtpSession?, request: FtpRequest?): FtpletResult { log?.invoke( TAG, "onAppendStart argument = ${request?.argument} , requestLine = ${request?.requestLine} , command = ${request?.command}" ) return super.onAppendStart(session, request) } override fun onAppendEnd(session: FtpSession?, request: FtpRequest?): FtpletResult { log?.invoke( TAG, "onAppendEnd argument = ${request?.argument} , requestLine = ${request?.requestLine} , command = ${request?.command}" ) return super.onAppendEnd(session, request) } override fun onLogin(session: FtpSession?, request: FtpRequest?): FtpletResult { log?.invoke(TAG, "onLogin argument = ${request?.argument} , requestLine = ${request?.requestLine} , command = ${request?.command}") return super.onLogin(session, request) } override fun onConnect(session: FtpSession?): FtpletResult { log?.invoke(TAG, "onConnect ") return super.onConnect(session) } override fun onDisconnect(session: FtpSession?): FtpletResult { log?.invoke(TAG, "onDisconnect ") return super.onDisconnect(session) } override fun onUploadStart(session: FtpSession?, request: FtpRequest?): FtpletResult { log?.invoke( TAG, "onUploadStart argument = ${request?.argument} , requestLine = ${request?.requestLine} , command = ${request?.command}" ) return super.onUploadStart(session, request) } override fun onUploadEnd(session: FtpSession?, request: FtpRequest?): FtpletResult { log?.invoke( TAG, "onUploadEnd argument = ${request?.argument} , requestLine = ${request?.requestLine} , command = ${request?.command}" ) return super.onUploadEnd(session, request) } override fun onDownloadStart(session: FtpSession?, request: FtpRequest?): FtpletResult { log?.invoke( TAG, "onDownloadStart argument = ${request?.argument} , requestLine = ${request?.requestLine} , command = ${request?.command}" ) return super.onDownloadStart(session, request) } override fun onDownloadEnd(session: FtpSession?, request: FtpRequest?): FtpletResult { log?.invoke( TAG, "onDownloadEnd argument = ${request?.argument} , requestLine = ${request?.requestLine} , command = ${request?.command}" ) return super.onDownloadEnd(session, request) } } 2 客户端

引入库:

//ftp implementation 'commons-net:commons-net:3.8.0' implementation files('libs/ftpserver-core-1.0.6.jar') 2.1 客户端的代码实现 import android.net.Uri import android.util.Log import com.demo.client.model.ClientConfig import kotlinx.coroutines.* import org.apache.commons.net.ftp.FTPClient import org.apache.commons.net.ftp.FTPReply import java.io.* import java.net.SocketException class FtpClientManager { companion object { private const val TAG = "FtpClient" private const val BUFFER_SIZE = 2 * 1024 * 1024 val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { FtpClientManager() } } private val job = SupervisorJob() private val scope = CoroutineScope(Dispatchers.IO + job) var ilog: ((tag: String, content: String?) -> Unit)? = null private var ftpClient: FTPClient? = null private var config: ClientConfig? = null fun connect2Server(config: ClientConfig, callback: ((result: Boolean) -> Unit)? = null) { this.config = config ilog?.invoke(TAG, config.toString()) val ftpUri = Uri.parse(config.ftpUrl) ftpClient = FTPClient() //设定连接超时时间 ftpClient?.connectTimeout = config.connectTimeout.toInt() ftpClient?.setDataTimeout(config.connectTimeout.toInt()) ilog?.invoke(TAG, "ftpUri = ${ftpUri.host} , ${ftpUri.port}") scope.launch { try { // 要连接的FTP服务器Url,Port ftpClient?.connect(ftpUri.host, ftpUri.port) // 看返回的值是不是230,如果是,表示登陆成功 val reply = ftpClient?.replyCode ilog?.invoke(TAG, "reply = $reply") if (!FTPReply.isPositiveCompletion(reply!!)) { // 断开 ftpClient?.disconnect() withContext(Dispatchers.Main) { callback?.invoke(false) } return@launch } // 登陆FTP服务器 val login = ftpClient?.login(config.ftpUserName ?: "anonymous", config.ftpUserPwd) ilog?.invoke(TAG, "login = $login") if (!login!!) { // 断开 ftpClient?.disconnect() withContext(Dispatchers.Main) { callback?.invoke(false) } return@launch } ftpClient?.setFileType(FTPClient.BINARY_FILE_TYPE) ftpClient?.enterLocalPassiveMode() withContext(Dispatchers.Main) { callback?.invoke(true) } } catch (e: SocketException) { e.printStackTrace() withContext(Dispatchers.Main) { callback?.invoke(false) } } catch (e: IOException) { e.printStackTrace() withContext(Dispatchers.Main) { callback?.invoke(false) } } } } fun disconnectFTP(): Boolean { return try { ftpClient?.disconnect() true } catch (e: IOException) { e.printStackTrace() false } } /** * 下载文件 * * @param saveFilePath 要存放的文件的路径 * @param remoteFileName 远程FTP服务器上的那个文件的名字 * @param callback true为成功,false为失败 */ fun downloadFile(saveFilePath: String, remoteFileName: String, callback: ((result: Boolean) -> Unit)? = null) { if (null == ftpClient) { callback?.invoke(false) return } if (!ftpClient!!.isConnected) { connect2Server(config!!) { result -> if (result) { realDownload(saveFilePath, remoteFileName, callback) } } } else { realDownload(saveFilePath, remoteFileName, callback) } } private fun realDownload(saveFilePath: String, remoteFileName: String, callback: ((result: Boolean) -> Unit)? = null) { scope.launch { var out: BufferedOutputStream? = null try { val workPath = ftpClient?.printWorkingDirectory() ilog?.invoke(TAG, "realDownload workPath = $workPath") if ("/" == workPath) { //工作目录切换,按需看自己是否需要切换 ftpClient?.changeWorkingDirectory("/resources/") } ftpClient?.bufferSize = BUFFER_SIZE val files = ftpClient!!.listFiles(remoteFileName) if (null == files || files.isEmpty()) { throw FileNotFoundException("not found remoteFileName") } val fileInfo = files[0] val localFile = File(saveFilePath) out = BufferedOutputStream(FileOutputStream(localFile)) val downFlag = ftpClient!!.retrieveFile(fileInfo.name, out) out.flush() withContext(Dispatchers.Main) { callback?.invoke(downFlag) } } catch (e: Exception) { e.printStackTrace() withContext(Dispatchers.Main) { callback?.invoke(false) } } finally { out?.close() // 退出登陆FTP,关闭ftpCLient的连接 ftpClient?.logout() ftpClient?.disconnect() } } } /** * 上传文件 * * @param uploadFilePath 要上传文件所在SDCard的路径 * @param callback true为成功,false为失败 */ fun uploadFile(uploadFilePath: String, callback: ((result: Boolean) -> Unit)? = null) { if (null == ftpClient) { callback?.invoke(false) return } if (!ftpClient!!.isConnected) { connect2Server(config!!) { result -> if (result) { realUpload(uploadFilePath, callback) } } } else { realUpload(uploadFilePath, callback) } } private fun realUpload(uploadFilePath: String, callback: ((result: Boolean) -> Unit)? = null) { val uoloadFile = File(uploadFilePath) if (!uoloadFile.exists()) { callback?.invoke(false) return } scope.launch { val workPath = ftpClient?.printWorkingDirectory() ilog?.invoke(TAG, "realUpload workPath = $workPath") if ("/" == workPath) { //工作目录切换,按需看自己是否需要切换 ftpClient?.changeWorkingDirectory("/resources/") } // 设置上传文件需要的一些基本信息 ftpClient?.bufferSize = BUFFER_SIZE ftpClient?.controlEncoding = "UTF-8" ftpClient?.enterLocalPassiveMode() var fileInputStream: FileInputStream? = null try { fileInputStream = FileInputStream(uploadFilePath) val uploadFlag = ftpClient!!.storeFile(uoloadFile.name, fileInputStream) withContext(Dispatchers.Main) { callback?.invoke(uploadFlag) } } catch (e: Exception) { e.printStackTrace() withContext(Dispatchers.Main) { callback?.invoke(false) } } finally { fileInputStream?.close() // 退出登陆FTP,关闭ftpCLient的连接 ftpClient?.logout() ftpClient?.disconnect() } } } } 附件

依赖库下载地址:

https://mina.apache.org/downloads-mina_2_0.html

https://mina.apache.org/ftpserver-project/old-downloads.html



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3